<?php
// +----------------------------------------------------------------------
// | Author: Stupboy King
// +----------------------------------------------------------------------
namespace app\api\model;
use app\api\logic\Gps;
use app\base\service\Beidou;
use app\base\service\JavaGps;
use think\Config;
use think\Db;
use think\Hook;

class Order extends Common {

    /**
     * 关联GPS表 一对一
     */
    public function ordergps() {
        return $this->hasOne('OrderGps', 'order_id', 'order_id');
    }

    /**
     * 乘客表 一对一
     */
    public function passenger(){
        return $this->hasOne('Passenger','passenger_id','passenger_id');
    }

    /**
     * 审核人表 一对一
     */
    public function approvalPassenger(){
        return $this->hasOne('Passenger','passenger_id','approval_id');
    }

    /**
     * 关联司机表 一对一
     */
    public function driver(){
        return $this->hasOne('Driver','driver_id','driver_id');
    }
    
    /**
     * 关联车辆表 一对一
     */
    public function car(){
        return $this->hasOne('Car','car_id','car_id');
    }

    public function cartype(){
        return $this->hasOne('CarType','car_type_id','car_type_id');
    }
    
    /**
     * 关联费用表 一对一
     */
    public function orderfee(){
        return $this->hasOne('OrderFee','order_id','order_id');
    }
    

    public function receiveOrder($oid, $driver_id) {
        return $this->save(['order_state' => 4, 'driver_id' => $driver_id], ['order_id' => $oid, 'driver_id' => null]);
    }

    /**
     * 获取订单列表
     * @param int $driver_id 司机id
     * @param int $car_type_id 车型id
     * @param datetime $start_time 开始时间
     * @param datetime $end_time 结束时间
     * @param int $order_state 0:历史订单，1:当前订单
     */
    public function getOrderList($driver_id, $car_type, $start_time, $end_time, $order_state, $use_type, $order_type, $booking_type, $page = 1, $pageSize = 10) {
        $whereBase              = " driver_id = $driver_id ";
        $whereBase             .= " and order_state in (5,6,7,8) ";
        $where                  = " driver_id = $driver_id ";
        $where                 .= " and `order`.delete_time is null ";
        $order_state && $where .= " and order_state in ( $order_state ) ";
        $car_type    && $where .= " and car_type in ( $car_type ) ";
        $start_time  && $where .= " and plan_time >= '$start_time' ";
        $end_time    && $where .= " and plan_time <= '$end_time' ";

        $orderField = 'order_id,order_no,order_state,order_type,use_type,booking_type,order_time,order.car_type_id,driver_id';
        $gpsField   = 'from_addr departure,from_lon,from_lat,to_addr destination,to_lon,to_lat,ifnull(plan_time,call_time) plan_time, go_time';
        $typeField  = 'car_type_name car_type_text';
        $count      = Db::view('order',[$orderField])
            ->view('order_gps',[$gpsField],'order.order_id = order_gps.order_id','left')
            ->where($where)
            ->whereOr($whereBase)
            ->count();
        $data       = Db::view('order',[$orderField])
            ->view('order_gps',[$gpsField],'order.order_id = order_gps.order_id','left')
            ->view('car_type',[$typeField],'order.car_type_id = car_type.car_type_id')
            ->where($where)
            ->whereOr($whereBase)
            ->page($page,$pageSize)->order('order_state,order_id desc')->select();
        $temp       = [];
        foreach($data as $v){
            $orderType = Config::get('base.order_types');
            $useType   = Config::get('base.use_types');
            $bookType  = Config::get('base.booking_types');
            $v['order_type_text']   = $orderType[$v['order_type']];
            $v['use_type_text']     = $useType[$v['use_type']];
            $v['car_type_text']     = empty($v['car_type_text']) ? '未知' : $v['car_type_text'];
            $v['booking_type_text'] = $bookType[$v['booking_type']];
            $temp[] = $v;
        }
        return [$count,$temp];
    }

    /**
     * 获取附近发单
     * @param $type 订单类型
     * @param int $driver 司机id
     * @param int $page 页数
     * @param int $num 记录数
     * TODO 根据司机经纬度及查询类型查询附近乘客发单
     * @return array
     */
    public function getNearOrder($type=1,$page=1,$num=10,$driver_id=0){
        $time        = time() + ($type-1)*24*60*60;
        $start_time  = date('Y-m-d',$time)." 00:00:00";
        $end_time    = date('Y-m-d',$time)." 23:59:59";
        if($driver_id>0){
            // TODO 司机定位附近订单判断
            $orderField = 'order_id,order_state,order_type,use_type,booking_type,order_time,0 car_type_id,departure,destination';
            $gpsField   = 'from_addr,from_lon,from_lat,to_addr,to_lon,to_lat,plan_time';
            $result     = Db::view('order',[$orderField])
                ->view('order_gps',[$gpsField],'order.order_id = order_gps.order_id','left')
                ->where("order_state",5)
                ->where('driver_id',$driver_id)
                ->where("plan_time between  '$start_time' and '$end_time' ")
                ->page($page,$num)
                ->select();
            if(!empty($result)){
                return [count($result),$result];
            }
        }
        $orderField = 'order_id,order_state,order_type,use_type,booking_type,order_time,car_type_id,departure,destination';
        $gpsField   = 'from_addr,from_lon,from_lat,to_addr,to_lon,to_lat,plan_time';
        $result     = Db::view('order',[$orderField])
            ->view('order_gps',[$gpsField],'order.order_id = order_gps.order_id','left')
            ->where("order_state",4)
            ->where('driver_id',null)
            ->where("plan_time between  '$start_time' and '$end_time' ")
            ->page($page,$num)
            ->select();
        return [count($result),$result];
    }

    /**
     * 获取订单详情
     * @param int $order_id 订单id
     * @return array 订单详情
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function getOrderDetail($order_id) {
        $order                   = $this
            ->alias('o')
            ->join('passenger p', 'o.passenger_id = p.passenger_id', 'left')
            ->join('car_type ct','o.car_type_id = ct.car_type_id', 'left')
            ->join('car c','o.car_id = c.car_id', 'left')
            ->where('order_id', $order_id)
            ->field('o.*, p.head_portrait, ct.car_type_name,c.number as origin_car_number,p.phone apply_phone')
            ->find();
        if($order['head_portrait']) {
            $arr      = explode('/',$order['head_portrait']);
            $data['head_portrait'] = Config::get('base.web_url') . '/upload/head_portrait/' .$arr[count($arr)-2] . '/' . $arr[count($arr)-1];
        }else{
            $data['head_portrait'] = '';
        }
        $data['driver_id']       = $order['driver_id'];
        $data['passenger_name']  = $order['passenger_name'];
        $data['passenger_phone'] = $order['passenger_phone'];
        $data['apply_phone']     = $order['apply_phone'];
        $data['from_lon']        = $order->ordergps ? $order->ordergps['from_lon'] : '';
        $data['from_lat']        = $order->ordergps ? $order->ordergps['from_lat'] : '';
        $data['from_addr']       = $order->ordergps ? $order->ordergps['from_addr'] : '';
        $data['to_lon']          = $order->ordergps ? $order->ordergps['to_lon'] : '';
        $data['to_lat']          = $order->ordergps ? $order->ordergps['to_lat'] : '';
        $data['to_addr']         = $order->ordergps ? $order->ordergps['to_addr'] : '';
        $data['use_time']        = $order->ordergps ? $order->ordergps['plan_time'] : '';
        $data['go_time']         = $order->ordergps ? $order->ordergps['go_time'] : '';
        $data['driver_money']    = $order->orderfee ? $order->orderfee['driver_money'] : 0;
        $data['order_state']     = $order['order_state'];
        $data['car_number']     = $order['origin_car_number'];
        $data['car_type_text']     = $order['car_type_name'];
        // TODO 费用列表
        return $data;
    }
    
    public static function checkFinishParam($param){
        $data['wait_time'] = isset($param['wait_time']) ? $param['wait_time'] : 0;
        $data['wait_fee']  = isset($param['wait_fee'])  ? $param['wait_fee']  : 0;
        if(!isset($param['use_time'])){
            return [0,'累积时长不能为空'];
        }
        $data['use_time']   = $param['use_time'];
        $data['time_fee']   = isset($param['time_fee'])  ? $param['time_fee']  : 0;
        if(!isset($param['total_meter'])){
            return [0,'累积里程不能为空'];
        }
        $data['total_meter'] = $param['total_meter'];
        $data['meter_fee']   = isset($param['meter_fee'])  ? $param['meter_fee']  : 0;
        $data['low_time']    = isset($param['low_time'])   ? $param['low_time']  : 0;
        $data['low_fee']     = isset($param['low_fee'])   ? $param['low_fee']  : 0;
        $data['night_meter'] = isset($param['night_meter'])   ? $param['night_meter']  : 0;
        $data['night_fee']   = isset($param['night_fee'])   ? $param['night_fee']  : 0;
        $data['high_fee']    = isset($param['high_fee'])   ? $param['high_fee']  : 0;
        $data['toll']        = isset($param['toll'])   ? $param['toll']  : 0;
        $data['park_fee']    = isset($param['park_fee'])   ? $param['park_fee']  : 0;
        $data['other_fee']   = isset($param['other_fee'])   ? $param['other_fee']  : 0;
        if($data['other_fee']>0){
            return [0,'必须填写费用备注'];
        }
        $data['other_note']  = isset($param['other_note'])   ? $param['other_note']  : 0;
        if(!isset($param['money'])){
            return [0,'费用不能为空'];
        }
        $data['money']       = $param['money'];
        $data['order_state'] = 7;
        return [1,0,$data];
    }

    /**
     * @param int $oid
     * @return mixed
     * @throws \think\exception\DbException
     */
    public function getTrack($oid=1102){
        $order     = $this->get($oid);
        $orderNo   = $order->getAttr('order_no');
        if(strlen($orderNo)==24){
            return $this->getNewTrack($oid);
        }
        // 获取北斗轨迹，北斗为空时用GPS轨迹
        $driver_id = $order->getAttr('driver_id');
        $startTime = $order->getAttr('ride_time');
        $endTime   = $order->ordergps->getAttr('arrival_time');
//        $carNumber = $order->getAttr('car_number');
//        $t1        = strtotime($startTime);
//        $t2        = strtotime($endTime);
//        $beiDou    = new Beidou();
        // $beiDouTrack = $beiDou->getTrack($carNumber,$t1,$t2,1);
        // 如果存在北斗轨迹则显示北斗轨迹
        // if(!empty($beiDouTrack)) return json_encode(['result'=>0,'data'=>$beiDouTrack]);
        $newGps = (new \app\api\logic\Gps())->getTrack($driver_id,$startTime,$endTime);
        if(!empty($newGps[3])){
            $track = $newGps[3];
        }else{
            $javaGps = (new JavaGps())->getTrack($driver_id,$startTime,$endTime,1);
            list($track,$d) = (new \app\api\logic\Gps())->fixGps($javaGps);
        }
        $ret  = json_encode(['result'=>0,'data'=>$track]);
        return $ret;
    }

    public function checkNewException($oid){
        $timeCheck = 0;
        $meterCheck= 0;
        $where['order_id'] = $oid;
        $gps = Db::name('order_gps')->where($where)->find();
        $fee = Db::name('order_fee')->where($where)->find();
        $fromCheck    = getGpsDistance($gps['from_lon'],$gps['from_lat'],$gps['go_lon'],$gps['go_lat']);
        $arrivalCheck = empty($gps['arrival_lon']) ? 0 : getGpsDistance($gps['to_lon'],$gps['to_lat'],$gps['arrival_lon'],$gps['arrival_lat']);
        $fee['use_time'] && $timeCheck    = $fee['use_time'] / $fee['pre_time'] > 1.5 ? $fee['use_time'] / $fee['pre_time'] : 0;
        $fee['meter'] && $meterCheck   = $fee['meter'] / $fee['pre_meter'] > 1.5 ? $fee['meter'] / $fee['pre_meter'] : 0;
        return $this->addOrderException($oid,$fromCheck,$arrivalCheck,$timeCheck,$meterCheck);
    }

    public function checkException($oid){
        $order     = $this->get($oid);
        $orderNo   = $order->getAttr('order_no');
        if(strlen($orderNo)>18){//只处理旧订单
            return 0;
        }
        $driver_id = $order->getAttr('driver_id');
        $startTime = $order->ordergps->getAttr('go_time');
        $endTime   = $order->ordergps->getAttr('arrival_time');
        $track     = (new JavaGps())->getTrack($driver_id,$startTime,$endTime,1);
        $count     = count($track);
        $data['from_lon'] = $order->ordergps->getAttr('from_lon');
        $data['from_lat'] = $order->ordergps->getAttr('from_lat');
        $data['to_lon']   = $order->ordergps->getAttr('to_lon');
        $data['to_lat']   = $order->ordergps->getAttr('to_lat');
        $data['pre_time']  = $order->orderfee->getAttr('pre_time');
        $data['pre_meter'] = $order->orderfee->getAttr('pre_meter');
        $fromCheck    = getGpsDistance($track[0]['longitude'],$track[0]['latitude'],$data['from_lon'],$data['from_lat']);
        $arrivalCheck = getGpsDistance($track[$count-1]['longitude'],$track[$count-1]['latitude'],$data['to_lon'],$data['to_lat']);
        $gps          = new Gps();
        $start['longitude'] = $data['from_lon'];
        $start['latitude']  = $data['from_lat'];
        $end['longitude']   = $data['to_lon'];
        $end['latitude']    = $data['to_lat'];
        $isBooking  = $order->getAttr('booking_type');
        if($isBooking==2){
            $time  = $order->cartype ? $order->cartype->getAttr('chartered_hour') : 0;
            $meter = $order->cartype ? $order->cartype->getAttr('chartered_km') : 0;//chartered_hour
            $preTime[0] = $time*3600;
            $preTime[1] = $meter*1000;
        }else{
            $preTime            = $gps->getOverTimeDistance($start,$end,2);
        }
        $arrivalCheck = $arrivalCheck > 10000000 ? 0 : $arrivalCheck;
        $useTime   = $order->orderfee->getAttr('use_time');
        $meter     = $order->orderfee->getAttr('meter');
        $timeCheck = $useTime / $preTime[0] > 1.5 ? $useTime / $preTime[0] : 0 ;
        $meterCheck= $meter / $preTime[1]   > 1.5 ? $meter / $preTime[1] : 0;
        return $this->addOrderException($oid,$fromCheck,$arrivalCheck,$timeCheck,$meterCheck);
    }

    public function checkOldException($oid){
        $allot = Db::query("SELECT d.apply_number,a.go_time,a.arrival_time,c.from_lon,c.from_lat,c.to_lon,c.to_lat,p_name,d.tag,e.real_name,a.driver_id FROM  jjcx_com.order_allot a left join jjcx_com.order_apply_allot b on a.id =b.allot_id left join jjcx_com.order_apply_detail c on b.apply_id = c.apply_id left join jjcx_com.order_apply d on b.apply_id = d.id left join jjcx_com.driver e on a.driver_id = e.id where a.id = $oid ");
        $order     = $allot[0];
        $driver_id = $order['driver_id'];
        $startTime = $order['go_time'];
        $checkType = empty($order['arrival_time']) ? 0 : 1;
        $endTime   = empty($order['arrival_time']) ? date('Y-m-d H:i:s') : $order['arrival_time'];
        $GPS       = (new JavaGps())->getTrack($driver_id,$startTime,$endTime,1);
        $s1 = $GPS[0]; $s2 = $GPS[1]; $s3 = $GPS[count($GPS)-1]; $s4 = $GPS[count($GPS)-2];
        $fromCheck    = $checkType==1 ? 0 : getGpsDistance($s1['longitude'],$s1['latitude'],$order['from_lon'],$order['from_lat']);
        $arrivalCheck = $checkType==0 ? 0 : getGpsDistance($s3['longitude'],$s3['latitude'],$order['to_lon'],$order['to_lat']);
        $arrivalCheck = $arrivalCheck > 10000000 ? 0 : $arrivalCheck;
        $timeCheck = 0;
        $meterCheck= 0;
        return $this->addOrderException($order,$fromCheck,$arrivalCheck,$timeCheck,$meterCheck,1);
    }

    public function addOrderException($oid,$fromCheck,$arrivalCheck,$timeCheck,$meterCheck,$type=0){
        $exceptionStr = [];
        $exceptionCode= 0;
        $fromCheck > 500 && $exceptionStr[] = '出发地偏移'.round($fromCheck,1).'米';
        $fromCheck > 500 && $exceptionCode  = $exceptionCode + 1;
        $arrivalCheck > 500 && $exceptionStr[] = '目的地偏移'.round($arrivalCheck,1).'米';
        $arrivalCheck > 500 && $exceptionCode  = $exceptionCode + 2;
        $timeCheck && $exceptionStr[] = '超过预计时间'.round($timeCheck,1).'倍';
        $timeCheck && $exceptionCode  = $exceptionCode + 4;
        // 关闭里程检测
        // $meterCheck && $exceptionStr[] = '超过预计里程'.round($meterCheck,1).'倍';
        // $meterCheck && $exceptionCode  = $exceptionCode + 8;
        if($type==0){
            $data['order_id']       = $oid;
            $data['exception_type'] = $exceptionCode;
            $data['exception_desc'] = implode(';',$exceptionStr);
            $data['add_time']       = date('Y-m-d H:i:s');
            if($exceptionCode==0) return 0;
            Db::name('order_exception')->where('order_id',$oid)->delete();
            // 删除旧系统时候预警
            $orderNo = Db::name('order')->where('order_id',$oid)->value('order_no');
            // 保留出发和目的地 轨迹预警记录
            // Db::name('order_exception')->where('apply_number',$orderNo)->delete();
            return Db::name('order_exception')->insert($data);
        }
        if($type==1){
            $data['apply_number'] = $oid['apply_number'];
            $data['order_text']   = $oid['real_name'].'$$'.$oid['p_name'];
            $data['order_id']     = 0;
            $data['exception_type'] = $exceptionCode;
            $data['exception_desc'] = implode(';',$exceptionStr);
            $data['add_time'] = date('Y-m-d H:i:s');
            if($exceptionCode==0) return 0;
            return Db::name('order_exception')->insert($data);
        }
    }

    public function getNewTrack($oid=0){
        $info = $this->alias('a')->where('a.order_id',$oid)
            ->join('order_gps b','a.order_id = b.order_id','left')
            ->field('a.driver_id,b.go_time,b.arrival_time,a.car_number')
            ->find();
        $data = (new \app\api\logic\Gps())->getTrack($info['driver_id'],$info['go_time'],$info['arrival_time']);
        $ret  = json_encode(['result'=>0,'data'=>$data[3]]);
        return $ret;
    }

    /**
     * 乘客或审核人 取消订单
     */
    public function cancelOrder($oid=0,$osn='',$pid=0, $need_cancel_fee = false, $is_admin = false){
        // TODO 超时取消转为未支付 否则转取消订单
        if($oid==0 && empty($osn)){
            return [0,'订单ID和订单号不能同时为空'];
        }
        $where = [];
        $oid > 0 && $where['a.order_id']    = $oid;
        !empty($osn) && $where['order_no'] = $osn;
        $field = 'a.passenger_id,a.approval_id,a.order_state,b.go_time,b.driver_time,a.driver_id,a.car_type_id,a.order_id';
        $info  = $this->alias('a')
            ->join('order_gps b','a.order_id = b.order_id','left')
            ->where('a.order_id',$oid)
            ->field($field)
            ->find();
        if($info['passenger_id'] != $pid && $is_admin === false){
            return [0,'只有申请人可以取消订单'];
        }
        $allowArr = [1,2,4,5,6,7];
        if(!in_array($info['order_state'],$allowArr)){
            return [0,'订单无法取消'];
        }
        if(!empty($info['go_time'])){
            return [0,'已出发订单无法取消'];
        }
        $cancelTime = empty($info['driver_time']) ? 0 : time() - strtotime($info['driver_time']);//司机出发时间判断
        $cancelState= $cancelTime>300 && $need_cancel_fee ? 9 : 12;

        // 产生取消费用
        $updateFee = [
            'cancel_time' => time()
        ];
        if($cancelState === 9) {
            $car_type = null;
            if($info['car_type_id']){
                $car_type = Db::name('car_type')->where('car_type_id', $info['car_type_id'])->find();
            }

            if(!$car_type || !$car_type['p_cancel_cost'] || $car_type['p_cancel_cost'] < 0){
                // 未设置取消费
                $cancelState = 12;
            }else {
                $updateFee['cancel_fee'] = $car_type['p_cancel_cost'];
            }
        }

        $upWhere    = $oid == 0 ? ['order_no'=>$osn] : ['order_id'=>$oid];
        $this->save(['order_state'=>$cancelState],$upWhere);

        Db::name('order_fee')->where('order_id',$info['order_id'])->update($updateFee);

        $param = ['oid'=>$oid,'order_state'=>$cancelState,'uid'=>$pid, 'is_admin' => $is_admin];
        Db::name('driver')->where('driver_id',$info['driver_id'])->update(['work_state'=>3]);
        Hook::listen('cancel_order',$param);
        return [1,'ok'];
    }

    /**
     * 修改订单审核人
     * @param $data
     * @return array
     */
    public function changeApproval($data){
        // TODO 校验审核人是否与申请人同个部门
        $approval = Db::name('passenger')->find($data['approval_id']);
        if(empty($approval)) return [0,'审核人不存在'];
        $order = $this->where('order_id',$data['order_id'])->where('order_state',1)->find();
        if(empty($order)) return [0,'订单不存在'];
        if($order['approval_id']==$data['approval_id']) return [0,'审核人和原来一样'];
        $updateData = ['approval_id'=>$data['approval_id'],'approval'=>$data['approval']];
        $this->save($updateData,['order_id'=>$data['order_id']]);
        Hook::listen('use_car',$data['order_id']);
        return [1,'ok'];
    }

     /**
     * 巴士确认报价
     * @param $oid
     * @return array
     */
    public function sureBusPrice($oid){
        $where['order_id']    = $oid;
        $where['order_state'] = 23;

        $data['order_state']  = $order['pay_type'] == 1 ? 9 : 1;
        if($this->save($data,$where)){
            return [1,'ok'];
        }else{
            return [0,'订单不存在或状态不对'];
        }
    }
}
